#ifndef FORMAT_H_
#define FORMAT_H_

#include <glibmm.h>
#include <list>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>

#include "conf/attribute.h"
#include "conf.h"
#include "yellowpage.h"

namespace gpyp {

class VariableName : boost::noncopyable {
private:
  std::vector<Glib::ustring> name_;
  std::vector<Glib::ustring> args_;

  size_t counter_;

public:
  bool match(const Glib::ustring &n, bool end = true);
  void push(size_t count = 1);
  void reset();

  operator bool() const;
  bool operator!() const;
  bool get(const Glib::ustring *&n1,
           bool end = true) const;
  bool get(const Glib::ustring *&n1,
           const Glib::ustring *&n2,
           bool end = true) const;

  const std::vector<Glib::ustring> &get_name() const;
  bool get_arg(size_t idx, Glib::ustring &arg) const;

  size_t get_counter() const;

  static bool validate(const Glib::ustring &str, char prefix);

  VariableName(const Glib::ustring &name,
               size_t offset_s = 0,
               size_t offset_e = 0);
};

class FormatTermBase : boost::noncopyable {
protected:
  Glib::ustring delimiter_;
  Glib::ustring data_;

  void set_data(const Glib::ustring data, bool html);

public:
  virtual void prepare(RefChannel ch, bool html);
  virtual size_t calc_size();
  virtual bool empty();
  virtual bool format(Glib::ustring &str, bool setdelimiter);
  virtual int compare(RefChannel ch1, RefChannel ch2);

protected:
  FormatTermBase(const Glib::ustring &delimiter);
public:
  virtual ~FormatTermBase();
};
typedef boost::shared_ptr<FormatTermBase> RefFormatTerm;
typedef std::list<RefFormatTerm> RefFormatTermList;

class FormatTermProperty : public FormatTermBase {
protected:
  const Channel::Property &prop_;

public:
  virtual void prepare(RefChannel ch, bool html);
  virtual int compare(RefChannel ch1, RefChannel ch2);

  FormatTermProperty(const Glib::ustring &delimiter, const Channel::Property &prop);
};

template<typename T>
class FormatTermAttribute : public FormatTermBase {
protected:
  T attr_;

public:
  virtual void prepare(RefChannel ch, bool html) {
    set_data(attr_->to_string(), html);
  }

  FormatTermAttribute(const Glib::ustring &delimiter, T attr) :
    FormatTermBase(delimiter),
    attr_(attr)
  {
  }
};

template<typename T>
class FormatTermSlot : public FormatTermBase {
protected:
  sigc::slot<T> slot_;

public:
  virtual void prepare(RefChannel/* ch*/, bool html) {
    set_data(boost::lexical_cast<Glib::ustring>(slot_()), html);
  }

  FormatTermSlot(const Glib::ustring &delimiter, sigc::slot<T> slot) :
    FormatTermBase(delimiter),
    slot_(slot)
  {
  }
};

class FormatTermList : public FormatTermBase {
private:
  Conf              &conf_;
  RefYPCollection    ypcollection_;

  RefFormatTermList  terms_;

  char               bracket_s_;
  char               bracket_e_;
  Glib::ustring      prefix_;
  Glib::ustring      suffix_;

  void add_term(Glib::ustring &delimiter, const Channel::Property &prop);
  template<typename T>
  void add_term(Glib::ustring &delimiter, T attr) {
    RefFormatTerm term(new FormatTermAttribute<T>(delimiter, attr));
    terms_.push_back(term);
    delimiter.clear();
  }
  template<typename T>
  void add_term(Glib::ustring &delimiter, sigc::slot<T> slot) {
    terms_.push_back(RefFormatTerm(new FormatTermSlot<T>(delimiter, slot)));
    delimiter.clear();
  }

protected:
  virtual void prepare(RefChannel ch, bool html);
  virtual size_t calc_size();
  virtual bool empty();
  virtual bool format(Glib::ustring &str, bool setdelimiter);

public:
  virtual int compare(RefChannel ch1, RefChannel ch2);

  bool format(Glib::ustring &str, RefChannel ch, bool html);

  void parse(const Glib::ustring &format);

  FormatTermList(Conf &conf, RefYPCollection ypcollection,
                 const Glib::ustring &format = Glib::ustring(),
                 const Glib::ustring &delimiter = Glib::ustring(),
                 char bracket_s = '\0', char bracket_e = '\0');
};

}/*gpyp*/

#endif/*FORMAT_H_*/
